/**
 * 
 */
package qy.qyalgotrader.technical;

import java.time.ZonedDateTime;
import java.util.Map;

import qy.jalgotrade.bar.Bar;
import qy.jalgotrade.dataseries.BarDataSeries;
import qy.jalgotrade.dataseries.SequenceDataSeries;
import qy.jalgotrade.event.EventHandler;
import qy.qyalgotrader.utils.Constants;

/**
 * <pre>
 * Convergence & Divergence (VWAP) of Time-Sharing Diagram:
 * 
 * CDTS = (close - intradayVwap) / intradayVwap
 * </pre>
 * 
 * @author c-geo
 *
 */
public class CDTS extends SequenceDataSeries<Double> implements EventHandler {

	private BarDataSeries __barDataSeries;

	private boolean __usePctValue;

	private boolean __useAdjustedValues;

	/**
	 * 
	 * @param barDataSeries The BarDataSeries instance being filtered.
	 * @throws Exception
	 */
	public CDTS(BarDataSeries barDataSeries) throws Exception {

		this(barDataSeries, true, false, 0);
	}

	/**
	 * 
	 * @param barDataSeries The BarDataSeries instance being filtered.
	 * @param usePctValue   Show CDTS as percent value.
	 * @throws Exception
	 */
	public CDTS(BarDataSeries barDataSeries, boolean usePctValue) throws Exception {

		this(barDataSeries, usePctValue, false, 0);
	}

	/**
	 * 
	 * @param barDataSeries     The BarDataSeries instance being filtered.
	 * @param usePctValue       Show CDTS as percent value.
	 * @param useAdjustedValues
	 * @throws Exception
	 */
	public CDTS(BarDataSeries barDataSeries, boolean usePctValue, boolean useAdjustedValues) throws Exception {

		this(barDataSeries, usePctValue, useAdjustedValues, 0);
	}

	/**
	 * 
	 * @param barDataSeries     The BarDataSeries instance being filtered.
	 * @param usePctValue       Show CDTS as percent value.
	 * @param useAdjustedValues
	 * @param maxLen            The maximum number of values to hold. Once a bounded length is full,
	 *                          when new items are added, a corresponding number of items are discarded
	 *                          from the opposite end. If None then dataseries.DEFAULT_MAX_LEN is used.
	 * @throws Exception
	 */
	public CDTS(BarDataSeries barDataSeries, boolean usePctValue, boolean useAdjustedValues, int maxLen)
	        throws Exception {

		super(maxLen, Double.class);
		__barDataSeries = barDataSeries;
		__usePctValue = usePctValue;
		__useAdjustedValues = useAdjustedValues;

		__barDataSeries.getNewValueEvent().subscribe(this);
	}

	/* (non-Javadoc)
	 * @see qy.jalgotrade.event.EventHandler#handle(java.lang.String, java.util.Map)
	 */
	@Override
	public void handle(String eventName, Map<String, Object> params) throws Exception {

		BarDataSeries barDataSeries = (BarDataSeries) params.get("dataSeries");
		ZonedDateTime dateTime = (ZonedDateTime) params.get("dateTime");
		Bar aBar = (Bar) params.get("value");
		__onNewBar(barDataSeries, dateTime, aBar);
	}

	private void __onNewBar(BarDataSeries barDataSeries, ZonedDateTime dateTime, Bar aBar) throws Exception {

		double close = Double.NaN;
		double vwapIntraday = Double.NaN;
		if (aBar != null) {
			if (!__useAdjustedValues) {
				close = aBar.getClose();
			} else {
				close = aBar.getAdjClose();
			}
			vwapIntraday = aBar.getExtraColumns().get(Constants.BAR_FIELD_VWAP_INTRADAY);
		}

		if (!Double.isNaN(close) && !Double.isNaN(vwapIntraday)) {
			double cdtsVal = __usePctValue ? (close - vwapIntraday) / vwapIntraday * 100
			        : (close - vwapIntraday) / vwapIntraday;
			appendWithDateTime(dateTime, cdtsVal);
		} else {
			appendWithDateTime(dateTime, Double.NaN);
		}
	}
}
